---------------------------------------- Chapitre I - Les bases ----------------------------------------
Crackme2 - partie 2
Cible : CrackMe2
Outils nécessaires :
OllyDbg (by Oleh Yuschuk)
Cette 3eme solution est le keygenning. C'est l'art de créer un programme (keygen : KEY GEN
erator, générateur de clé) permettant de calculer un serial en fonction de différentes données
comme un nom par exemple. Pour cela, il faut étudier plus en profondeur le programme cible afin de trouver la méthode de calcul utilisée.
Reprenons le crackme2. Revenons au départ avec CTRL+F2 (ou ).
On relance le crackme2 avec F9 (ou
), on rentre le couple bidon
"Kirjo" / "12345", OK et on breake sur la 1ere
API. Un petit F8 (ou
) pour exécuter celle-ci
et on se retrouve là :
Comme précédemment, on peut voir que le nom est récupéré puis stocké à l'adresse 403150
. L'adresse est visible soit grâce au PUSH qui indique à la fonction où écrire ce qu'elle
récupère (1) soit dans la pile puisque l'adresse a été poussée dans celle-ci et qu'Olly nous indique
son contenu lorsqu'il s'agit de caractères ASCII (2). Nous allons utiliser à nouveau la technique du
BPM (breakpoint memory). Soit vous faites un clic droit dans le dump, puis Goto expression /
403150 soit vous faites un clic droit dans la pile sur l'adresse du name puis Follow in dump. Avant de poser
un nouveau BP, on va nettoyer les existants afin de breaker uniquement où cela nous arrange. Cliquer sur
(ou ALT+Y) :
Ici sont listés tous les memory breakpoints. On retrouve celui que l'on a posé tout à l'heure avec en 1 son
adresse (et le label qui nous permet de l'identifier rapidement), en 2 le type du BP (ici R pour
Read / lecture et W pour write / écriture) et en 3 son statut
(Active ou Disabled / désactivé). Clic droit sur la ligne, Disable et on est tranquille
(vous verrez que dans le dump notre BPM est toujours présent mais apparaît désormais en jaune). On retourne dans la
fenêtre code ( ou ALT+C). Clic droit sur la 1ere lettre du name
(ou sur 4Bh), Add label, "name", encore clic droit au même
endroit, Breakpoint, Memory ..., cochez Read access et Write access si ils
ne le sont pas déjà, OK. On relance avec F9 (ou
), on breake sur la 2eme API qui récupère le serial, F9 (ou
) et on breake dans le module KERNELBASE :
Nous le voyons en haut dans la barre de titre. Nous avons breaké ici sur un accès au name (en bas à droite de la fenêtre). Pour
revenir dans notre programme juste après le call qui a appelé cette fonction, nous allons utiliser Execute till return,
(ou CTRL+F9). Cela va nous permettre d'exécuter le code
jusqu'à la ligne suivant le prochain RET (rappelez-vous la configuration d'Olly au début de ce tutorial) sans passer par
toutes les lignes avec un F8. Un seul nous suffira cette fois-ci pour revenir dans le code du crackme (surveillez la barre de titre) :
Juste au-dessus de la ligne où nous sommes revenu, il y a un appel à la fonction lstrlenA (lSTR ingLENgthA / longueur de chaîne) avec comme argument le nom. Pas besoin d'explication sur cette fonction, d'autant qu'Olly nous indique la valeur de retour et où elle est stockée (EAX ). Vu que le code commence par travailler sur le nom, il est possible que l'on soit dans la routine qui calcule le bon serial. On va donc se mettre un repère (je vous montre cette astuce car même si elle n'est pas très utile ici, elle pourra vous servir lorsque vous tracerez des codes plus compliqué que celui-ci). Au début de la 1ere ligne de la boucle (4011130), vous pouvez voir le signe $ . Cela signifie que cette ligne est appelée par un CALL. Comme on avait fait dans le dump, on va poser un label sur cette ligne. Clic droit, Add label et saisissez "CalculSerial". Une fois cela fait, mettez-vous dans la fenêtre information sur la ligne Local call from ..., clic droit et vous pouvez voir d'où est effectué l'appel :
Si vous cliquez sur Goto call ..., vous arriverez directement sur la ligne d'appel :
Cette technique permet de remonter le code en suivant les calls. D'autre part, vous pouvez voir la nouvelle écriture du call vers notre routine. Cette
parenthèse refermée, traçons ligne par ligne avec F8 (ou )
et mettons en commentaire ce que fait le code (les commentaires sont accessibles soit avec clic droit / Add comment soit avec la
touche ";") :
Dans cette partie, il est facile de se rendre compte que le programme teste si un nom a été saisi puis vérifie si le nombre de caractères est inférieur à 20d (14 h).
Ici, de la même manière que pour le serial saisi, on modifie le nom en effectuant un XOR 13h (19 d) sur chaque caractère. On arrive ensuite sur la boucle que l'on a déjà étudiée (celle qui modifie le serial saisi), on va donc la passer rapidement en posant un BP (F2) à la sortie de celle-ci sur le POP EAX :
F9 (ou ) et on étudie la suite à coup de
F8 (ou
) :
Pour les 2 premières lignes, pas de problème, par contre la 3eme met dans EDI une adresse mémoire. On va aller voir ce qu'elle pourrait bien contenir. Faites un clic droit sur la ligne de code, Follow in Dump / Immediate constant. Le dump se positionne à l'adresse contenue dans la ligne de code et nous pouvons voir qu'il s'agit d'un emplacement vide, sans doute l'endroit où va être stocké le résultat des prochains calculs. Continuons notre analyse :
Le code (1) ne présente pas de difficultés, par contre en 40119A, on récupère
en mémoire une valeur que l'on charge dans DL. Pour savoir de quoi il s'agit, cliquez dans la fenêtre informations sur
la ligne contenant l'adresse (2) puis clic droit / Follow in Dump (3). Le dump
se positionne, on remonte d'une ligne pour une meilleure vue (4) et on voit qu'il s'agit du 5eme caractère (soit le dernier) du
nom modifié (5). Continuons l'analyse avec notre amie F8 (ou
) :
On passe ensuite à la comparaison du serial saisi et du serial qui vient d'être calculé. On a maintenant tous les éléments pour coder un keygen. Pour résumer :
Plus qu'à traduire cela dans votre langage préféré ...
Maintenant que vous avez acquis les bases du reversing, nous allons voir quelques exemples de comportement d'un programme à objectif commercial.